package gbench.appdemo.myworld.economy.society;

import lombok.Data;

import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;
import java.util.stream.*;

import gbench.appdemo.myworld.economy.demand.IDemand;
import gbench.appdemo.myworld.economy.strategy.EconomyEvent;
import gbench.appdemo.myworld.economy.strategy.IdeaDomain;
import gbench.appdemo.myworld.economy.strategy.RationalPersonModel;
import gbench.appdemo.myworld.market.SimpleMarket;
import gbench.appdemo.myworld.market.commodity.Commodity;

/**
 * 构建一个人类社会
 * @author gbench
 *
 */
@Data
public class Society {
    
    /**
     * 构建一个人类社会
     * 
     * @param name 社会名称
     * @param interval 需求统计间隔
     */
    public Society(final String name, final long interval) {
        this.name = name;
        this.interval = interval;
    }
    
    /**
     * 社会初始化
     * @param m 社区数量
     * @param n 每个社区中的人口数量
     */
    public Society initialize(final Integer m,final Integer n) {
        // 构造社区
        Stream.iterate(0, i->i+1).limit(m==null?1:m).forEach(id->{
            final var community = new CommunityPoupluation();
            this.communites.add(community);// 加入到社会主体之中
            Stream.iterate(0, j->j+1).limit(n==null?1:n).forEach(j->{
                final var individual = new Individual("张"+id);
                individual.setName("张"+id);
                community.addIndividual(individual);
            });// 为社区添加人口
        });
        
        return this;
    }
    
    /**
     * 重启人类社会
     */
    public void restart(SimpleMarket<Commodity>market,BiConsumer<Stream<Commodity>,IDemand> cs) {
        // 获取 市场有效商品
        final var names = market.getCommodityLicenses().stream()
            .map(e->e.getCommodity())
            .map(e->e.getName())
            .distinct() // 去重
            .collect(Collectors.toList());
        final var counter = new AtomicLong(0l);
        while(!this.stopFlag) {
            final var event = new EconomyEvent(counter.get());
            communites.stream().flatMap(e->e.getIndividuals().stream())
            .forEach(individual->{// 人们表达美好生活的愿望
                final var ideaDomain = new IdeaDomain(individual,names);
                final var behaviorModel = Optional.ofNullable(individual.getBehaviorModel()).orElse(rationalPerson);// 行为模型
                final var demand = individual.getDemand((d,owner)->{// 设计需求
                    final var idea = behaviorModel.getIdea(ideaDomain, event);
                    if (idea == null) {
                        d.setName(null);
                        return;// behaviorModel 没有得出想法
                    } else {
                        final var name = idea.getName();
                        d.setName(name);// 设置需求名称
                    }
                    // System.out.println("发布需求:"+d);
                });// demand
                if(demand.getName()!=null) {// 有效需求
                    final var objective = behaviorModel.getObjective(demand);
                    final var commodities = behaviorModel.getCommodities(objective, market);
                    cs.accept(commodities,demand);
                }else{// 非法需求
                    System.err.println(MessageFormat.format("事件{0} 没有 为 {1} 刺激出需求!", event,individual));
                }//if
            });
            
            System.out.println(MessageFormat.format("经济事件:{0}", event));
            
            try {
                Thread.sleep(this.interval);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counter.incrementAndGet();
        }// while
        
    }
    
    /**
     * 停止社会运行
     */
    public void stop() {
        this.stopFlag = true;
    }
    
    private String name;// 社会名称
    private  AtomicInteger counter = new AtomicInteger(1); // 计数器
    private long interval = 3000; // 需求访问间隔
    private boolean stopFlag=false; // 停止标记
    private RationalPersonModel rationalPerson= new RationalPersonModel();// 逻辑模型
    private List<CommunityPoupluation> communites = new LinkedList<>(); // 社区人口
}
